home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HAM Radio 3.2
/
Ham Radio Version 3.2 (Chestnut CD-ROMs)(1993).ISO
/
packet
/
pacstat
/
stats.c
< prev
next >
Wrap
Text File
|
1987-10-22
|
23KB
|
1,130 lines
/*
stats.c - monitor AX.25 channel and gather network performance
statistics.
Hardware: IBM PC or compatable with at least 1 serial port,
TNC with "KISS" firmware installed.
Other software: W0RLI or WA7MBL compatable serial BIOS such
as COMBIOS or MBBIOS. KISS software for
TNC.
Language = Microsoft C version 4.0, Microsoft Macro Assembler version 4.0
This source is distributed freely and may be copied and
redistributed with the following provisos:
You may not sell it, nor may you charge for making
copies beyond the actual cost of mailing and media.
Written by Skip Hansen WB6YMH and Harold Price NK6K.
Feedback is desired.
RCP/M (213) 541-2503 300/1200/2400 baud
or via packet WB6YMH @ WB6YMH-2 or
NK6K @ NK6K
Modification history:
8/10/87 WB6YMH: Initial release.
ver 1.0
10/18/87 First general release.
ver 1.1
*/
#include <stdio.h>
#include <time.h>
#include <dos.h>
#include "monfile.h"
/* configuration constants */
#define DUMP_INTERVAL 60*5 /* number of seconds between table dumps */
#define MAX_CIRCUIT 200 /* number of entrys in circuit table */
#define MAX_DIGIS 100 /* number of entrys in digi table */
/* misc constants */
#define FALSE 0
#define TRUE !FALSE
#define FEND 0300
#define FESC 0333
#define TFEND 0334
#define TFESC 0335
#define MIN_SIZE 17 /* minimum size of valid ax.25 frame */
#define MAX_SIZE 330 /* maximum size of a valid frame */
/* global variables */
union REGS inregs, outregs;
unsigned char frame_buf[1024]; /* incomming SLIP frame is assembled here */
int frame_size; /* number of bytes in frame, including CRC */
unsigned char *cp,c;
unsigned char getbyte();
unsigned long get_cd_active(); /* assembly interrupt routines */
unsigned long get_cd_inactive();
/* NET/ROM network header */
struct netrom {
char org_node[7];
char dest_node[7];
unsigned char ttl;
unsigned char cndx;
unsigned char cid;
unsigned char tx;
unsigned char rx;
unsigned char opcode;
union{
struct {
unsigned char p_wind;
char user[7];
char at_node[7];
} con;
struct {
unsigned char a_wind;
} con_ack;
struct {
char info[236];
} i;
} v;
};
struct netrom *netp;
/* NET/ROM routing table broadcast structure */
struct node_list{
unsigned char signature;
char mnemonic[6];
struct routes{
char dest_node[7];
char dest_mnemonic[6];
char best_neighbor[7];
unsigned char best_quality;
} route[11];
};
struct node_list *uip;
/* circuit table */
struct CIRCUIT_RECORD ctab[MAX_CIRCUIT];
/* digipeater table */
struct DIGI_RECORD dtab[MAX_DIGIS];
/* frequency wide statistics */
struct FREQ_RECORD freq;
/* misc variable used to trace state of circuit */
struct STATE_TABLE{
unsigned int n[8]; /* array of checksums of i frames by n(s) */
unsigned int digi_bits[8]; /* heard digipeater bit field */
unsigned int last_ui; /* checksum of last ui frame */
unsigned int ui_bits; /* heard digipeater bit field for ui */
unsigned int s_bits; /* heard digipeater bit fields for s */
unsigned char last_ns; /* last n(s) we heard */
unsigned char last_s; /* last control field we heard */
unsigned char first_digi; /* first digipeater we heard */
} stab[MAX_CIRCUIT];
int nr_circuits; /* number of active entrys in circuit table */
unsigned int nr_digis; /* number of active entrys in digipeater table */
unsigned char digi_num; /* number of digi current frame was heard from */
int nr_digi; /* total number of digis this connection */
unsigned int cnum; /* circuit number of current frame */
unsigned int dnum; /* circuit number of current frame for */
/* "non-digipeated" counters */
unsigned int i_size; /* size of data portion of UI or I frame */
char retry; /* retry flag */
char last_c; /* last character sent to screen */
unsigned char crtype; /* command/response flag */
unsigned char n_s;
unsigned int isum; /* checksum of data portion of UI or I frame */
unsigned int digi_bit; /* bit representing current hop */
unsigned long write_time,start_time;
/* parser variables */
int p_timestamp=0;
int p_baud=4800;
int p_port=0; /* COM1 */
int port_base = 0x3f8; /* COM1 */
char using_combios;
char ints_active;
main (argc, argv)
int argc;
char *argv[];
{
unsigned char to[10],from[10];
long cur_time;
int i,j;
unsigned char s[128];
printf("STATS version 1.1 - Packet radio network performance monitoring program\n");
printf("October 1987, written by WB6YMH and NK6K\n\n");
printf("Type ALT-C for command prompt.\n\n");
if (argc>1) { /* package up command line args for parser */
j=0;
for (i=1;i<argc;i++) {
while(*argv[i]!='\0') {
s[j]=*argv[i];
j++;
*argv[i]++;
}
s[j++]=' ';
}
s[j-1]='\0';
parse(1,s);
}
/* check for presence of COMBIOS for our com port */
inregs.h.ah = 4; /* Inquiry */
inregs.x.dx = p_port;
int86(0x14,&inregs,&outregs);
if(outregs.x.ax == 0xaa55){
ints_active = FALSE;
using_combios = TRUE;
}
else{
if(p_port < 0 || p_port > 1){
printf("Error: Port number must be COM1 or COM2 unless COMBIOS is loaded.\n");
exit(1);
}
serlinit(p_port);
using_combios = FALSE;
ints_active = TRUE;
}
if(p_port){
set_base(0x2f8); /* com2 */
}
else{
set_base(0x3f8); /* com1 */
}
tick_init();
nr_circuits = 0;
time(&start_time);
write_time = start_time + DUMP_INTERVAL;
init_freq();
while(1){
if(kbhit())
do_kbhit();
/* get a frame, check for reasonable frame size */
/* Some versions of KISS seem to pass bad frames */
/* once in a while which drives the monitoring */
/* code nuts if the frame is a runt. */
do{
get_frame();
} while( frame_size < MIN_SIZE || frame_size > MAX_SIZE);
cp=&frame_buf[1]; /* skip SLIP type byte */
/* put a null at the end of the frame for convience */
cp[frame_size-2]=0;
freq.t_packets++;
freq.t_bytes += frame_size;
if(frame_size <= 32)
freq.l32++;
else if(frame_size <=64)
freq.l64++;
else if(frame_size <= 128)
freq.l128++;
else if(frame_size <= 256)
freq.l256++;
else
freq.g256++;
if (p_timestamp) {
time(&cur_time);
printf("[%15.15s] ",ctime(&cur_time)+4);
}
pcall(cp+7,0);
bcall(cp+7,from);
putchar('>');
pcall(cp,0);
bcall(cp,to);
/* check for ax25v1 vs ax25v2 */
if ((cp[6] & 0x80) == (cp[13] & 0x80))
crtype='o';
else if (cp[6] & 0x80)
crtype='c';
else
crtype='r';
cp+=7;
/* print the digipeater list */
nr_digi = 0;
digi_num = 0;
digi_bit = 1;
while(!(cp[6] & 1)){
putchar(',');
nr_digi++;
pcall(cp+7,1);
if(cp[13] & 0x80 && (cp[13] & 1 || !(cp[20] & 0x80))){
do_digi(cp+7); /* update digi record */
digi_bit = 1 << nr_digi;
digi_num = nr_digi;
}
cp+=7;
}
cp+=7;
/* lookup this circuit in the tables */
find_circuit(from,to);
/* The global variable cnum points to current circuit. */
ctab[cnum].t_packets++;
ctab[cnum].t_bytes += frame_size;
if(*cp & 0x10) { /* p/f bit set */
if(crtype == 'c')
ctab[dnum].poll++;
else if(crtype == 'r')
ctab[dnum].final++;
}
/* Decode control field of frame to find frame type */
if(!(*cp & 1)){
do_iframe();
}
else if((*cp & 0xef) == 3){
do_ui();
}
else{
do_stype();
}
if(last_c != 0xd) /* prevent doublespaced output */
printf("\n");
last_c = 0;
/* The global variable dnum points to current circuit if */
/* and only if this is a "non-digipeated" frame otherwise */
/* dnum points to an unused entry in the table. This */
/* kluge helps to eliminate the need for tons of if */
/* statements. */
ctab[dnum].nd_packets++;
ctab[dnum].nd_bytes += frame_size;
/* now a few sanity checks */
if(ctab[cnum].u_dbytes > ctab[cnum].nd_dbytes){
printf("\007Error: U_dbytes > nd_dbytes!\n");
}
if(ctab[cnum].t_dbytes > ctab[cnum].t_bytes){
printf("\007Error: T_dbytes > t_bytes!\n");
}
}
}
do_iframe()
{
do_i_size(); /* Calculate size of data portion and checksum */
printf("{%d,%d,%c",(*cp & 0xe0) >> 5,n_s=(*cp & 0xe) >> 1,
crtype);
if(*cp & 0x10)
putchar('*');
cp++; /* point to pid */
ctab[cnum].pid = *cp;
if(stab[cnum].last_ns == n_s || /* expected n(s) */
/* - or - */
stab[cnum].n[n_s] != isum){ /* different i */
/* than last time*/
stab[cnum].last_ns = (n_s + 1) & 0x7;
stab[cnum].n[n_s] = isum;
stab[cnum].digi_bits[n_s] = 0;
ctab[cnum].u_dpackets++;
ctab[cnum].u_dbytes += i_size;
freq.u_packets++;
freq.u_bytes += frame_size;
if(i_size <= 32)
ctab[cnum].l32++;
else if(i_size <= 64)
ctab[cnum].l64++;
else if(i_size <= 128)
ctab[cnum].l128++;
else if(i_size <=256)
ctab[cnum].l256++;
else
ctab[cnum].g256++;
}
do_bitmap(&stab[cnum].digi_bits[n_s]);
ctab[dnum].i++;
ctab[cnum].t_dpackets++;
ctab[dnum].nd_dpackets++;
ctab[cnum].t_dbytes += i_size;
ctab[dnum].nd_dbytes += i_size;
if(retry)
printf(",retry");
putchar('}');
if(*cp == 0xcf) /* check for netrom PID */
do_netrom();
else
cp++; /* skip PID */
/* print data portion of frame */
while(*cp){
last_c = *cp;
if( (*cp & 0x7f) != 7)
putchar(*cp);
if(*cp == 0xd)
putchar(0xa);
cp++;
}
}
do_ui()
{
do_i_size(); /* Calculate size of data portion and checksum */
do_bitmap(&stab[cnum].s_bits);
printf("{ui,%c",crtype);
if(*cp & 0x10)
putchar('*');
if(stab[cnum].last_ui != isum){
/* unique frame if checksums is different than last UI frame */
stab[cnum].s_bits = 0;
freq.u_packets++;
ctab[cnum].u_dpackets++;
ctab[cnum].u_dbytes += i_size;
ctab[dnum].nd_dbytes += i_size;
freq.u_bytes += frame_size;
stab[cnum].last_ui = isum;
if(i_size <= 32)
ctab[cnum].l32++;
else if(i_size <= 64)
ctab[cnum].l64++;
else if(i_size <= 128)
ctab[cnum].l128++;
else if(i_size <=256)
ctab[cnum].l256++;
else
ctab[cnum].g256++;
}
if(retry)
printf(",retry");
putchar('}');
cp++; /* point to pid */
ctab[cnum].pid = *cp;
switch(*cp){
case 0xcf:
/* net/rom node list broadcast */
do_routes();
break;
case 0xcc:
/* ip frames */
do_ip();
break;
case 0xcd:
/* arp frames */
do_arp();
break;
case 0xf0:
/* "normal" ui frames */
cp++; /* skip pid */
while(*cp){
last_c = *cp;
if( (*cp & 0x7f) != 7)
putchar(*cp);
if(*cp == 0xd)
putchar(0xa);
cp++;
}
break;
default:
printf("Unknown PID in ui frame: 0x%02X\n",*cp);
break;
}
ctab[dnum].ui++;
ctab[cnum].t_dpackets++;
ctab[dnum].nd_dpackets++;
ctab[cnum].t_dbytes += i_size;
}
do_stype()
{
if(stab[cnum].last_s != *cp){
/* unique frame if control field is different than last frame */
stab[cnum].last_s = *cp;
stab[cnum].s_bits = 0;
freq.u_packets++;
freq.u_bytes += frame_size;
}
do_bitmap(&stab[cnum].s_bits);
switch(*cp & 0x3){
case 1: /* S type frames */
switch((*cp & 0xc) >> 2){
case 0:
ctab[dnum].rr++;
printf("{rr,%d",(*cp & 0xc0) >> 5);
break;
case 1:
printf("{rnr,%d",(*cp & 0xc0) >> 5);
ctab[dnum].rnr++;
break;
case 2:
printf("{rej,%d",(*cp & 0xc0) >> 5);
ctab[dnum].rej++;
break;
default:
printf("{unknown S type ctrl: 0x%X}",*cp);
return;
break;
}
break;
case 0x3: /* U frame types */
/* UI frames handled elsewhere */
switch(*cp & 0xef){
case 0x2f:
printf("{sabm");
ctab[dnum].sabm++;
break;
case 0x43:
printf("{disc");
ctab[dnum].disc++;
break;
case 0xf:
printf("{dm");
ctab[dnum].dm++;
break;
case 0x63:
printf("{ua");
ctab[dnum].ua++;
break;
case 0x87:
printf("{frmr!");
ctab[dnum].frmr++;
break;
default:
printf("{unknown frame type ctrl: 0x%02X}",*cp);
return;
}
break;
default:
printf("{unknown frame type ctrl: 0x%02X}",*cp);
return;
break;
}
printf(",%c",crtype);
if(*cp & 0x10)
putchar('*');
if(retry)
printf(",retry");
putchar('}');
}
/*
Decode and print NET/ROM network header
*/
do_netrom()
{
int i;
cp++; /* point to network header */
netp = (struct netrom *) cp;
printf("\n{netrom>");
pcall(netp->org_node);
putchar('>');
pcall(netp->dest_node);
printf(", ttl:%d, cndx:%d, ",netp->ttl,netp->cndx);
printf("cid:%d, tx:%d, rx:%d",netp->cid,netp->tx,netp->rx);
if(netp->opcode & 0x80)
printf(", Choke");
if(netp->opcode & 0x40)
printf(", Nak");
if(netp->opcode & 0x20)
printf(", More");
if(netp->opcode & 0x10)
printf(", Rsvd");
switch(netp->opcode & 0xf){
case 1:
printf(", Conn");
printf(", win:%d}\nuser:",netp->v.con.p_wind);
pcall(netp->v.con.user);
printf(" node:");
pcall(netp->v.con.at_node);
*cp = 0;
break;
case 2:
printf(", Conack");
printf(", win:%d}",netp->v.con_ack.a_wind);
*cp = 0;
break;
case 3:
printf(", Discon}");
*cp = 0;
break;
case 4:
printf(", Disack}");
*cp = 0;
break;
case 5:
printf(", iframe}\n");
cp = netp->v.i.info;
break;
case 6:
printf(", iack}");
*cp = 0;
break;
default:
printf("unknown opcode 0x%2X",netp->opcode);
printf("\n");
for(i=0; i< 13; i++)
printf("%x ",cp[i]);
printf("\n");
*cp = 0;
break;
}
}
/*
Decode and print NET/ROM routing broadcast
*/
do_routes()
{
int i, nr_nodes;
cp++;
uip = (struct node_list *) cp;
if(uip->signature != 0xff){
printf("Routing broadcast with unknown signature: 0x%02X\n",uip->signature);
return;
}
/* calculate number of nodes in this frame */
nr_nodes = (frame_size - 19) / sizeof(struct routes);
printf("Routing table broadcast from ");
p_mnem(uip->mnemonic);
printf("\n");
for(i=0; i < nr_nodes; i++){
p_mnem(uip->route[i].dest_mnemonic);
putchar(':');
pcall(uip->route[i].dest_node);
printf(" via ");
pcall(uip->route[i].best_neighbor);
printf(" quality: %d\n",uip->route[i].best_quality);
}
}
/*
Get a frame from the SLIP interface.
NOTE: leading type byte IS transfered into the buffer
*/
get_frame()
{
char *bptr;
bptr = frame_buf;
while(getbyte() != FEND); /* wait for start of frame */
while( (c = getbyte()) == FEND); /* ignore any extra FENDS */
frame_size = 0;
do{
if(c == FESC){
c = getbyte();
switch(c){
case TFEND:
*bptr++ = FEND;
frame_size++;
break;
case TFESC:
*bptr++ = FESC;
frame_size++;
break;
default:
break;
}
}
else{
*bptr++ = c;
frame_size++;
}
c = getbyte();
} while( c != FEND);
/* adjust for CRC bytes which are not transfered */
frame_size++;
}
/*
Get a byte from the serial line
*/
unsigned char getbyte()
{
int x,not_ready;
do{
if(kbhit())
do_kbhit();
if(time(0) >= write_time)
dump_data();
if(using_combios){
inregs.h.ah = 3; /* get com port status */
inregs.x.dx = p_port;
int86(0x14,&inregs,&outregs);
not_ready = !(outregs.h.ah & 1);
}
else{
x = rcvbyte();
not_ready = x == -1;
}
} while(not_ready);
if(using_combios){
inregs.h.ah = 2; /* read character */
int86(0x14,&inregs,&outregs);
return outregs.h.al;
}
else{
return x & 0xff;
}
}
/*
Print a 6 character mnemonic
*/
p_mnem(string)
char *string;
{
int i;
for(i=0; i < 6; i++)
putchar(*string++);
}
/*
Print IP datagram header
*/
do_ip()
{
printf("IP frame\n");
}
/*
Print ARP frame type
*/
do_arp()
{
printf("ARP frame\n");
}
/*
Locate entry in the statistics table for this circuit.
Generate a new entry if the circuit doesn't exist.
*/
find_circuit(from,to)
char *from;
char *to;
{
int i;
/* attempt to lookup existing circuit in table */
for(i=0; i < nr_circuits; i++){
if(!strcmp(ctab[i].to,to) && !strcmp(ctab[i].from,from)){
cnum = i;
return;
}
}
/* check for table overflow */
if(i == MAX_CIRCUIT){
dump_data();
err_exit("The circuit table is full!");
}
/* initialize new table entry */
nr_circuits++;
memset(&ctab[i],'\0',sizeof(struct CIRCUIT_RECORD));
memset(&stab[i],'\0',sizeof(struct STATE_TABLE));
strcpy(ctab[i].to,to);
strcpy(ctab[i].from,from);
ctab[i].digis = nr_digi;
time(&ctab[i].c_time); /* timestamp entry */
stab[i].last_s = 0; /* impossible sup type */
cnum = i;
}
/*
Compute size of data portion of I or UI frame types.
Calculate Checksum on data portion.
*/
do_i_size()
{
unsigned char *tmp;
int x;
/* cp is currently pointing at the frames control byte */
i_size = frame_size - (cp - &frame_buf[1]) - 4;
/* calculate checksum of data portion of the frame */
isum = 0;
tmp = cp;
x = i_size + 1;
tmp++; /* point to pid byte */
/* calculate checksum of I portion of frame */
while(x--){
isum += *tmp++;
}
}
/*
Dump the statistic tables to disk
*/
dump_data()
{
int i;
FILE *fp;
freq.dcd_on_ticks = get_cd_active();
freq.dcd_off_ticks = get_cd_inactive();
if(!(fp = fopen("LOG","a")))
err_exit("Opening LOG file.");
fprintf(fp,"T,%lu\n",start_time);
fprintf(fp,"F,%lu,%lu,%lu,",freq.t_packets,freq.t_bytes,freq.u_packets);
fprintf(fp,"%lu,%lu,%lu,",freq.u_bytes,freq.l32,freq.l64);
fprintf(fp,"%lu,%lu,%lu,",freq.l128,freq.l256,freq.g256);
fprintf(fp,"%lu,%lu\n",freq.dcd_on_ticks,freq.dcd_off_ticks);
printf("\n\n { Opening log file at %s",ctime(&start_time));
printf(" Writing %d digipeater records...",nr_digis);
for(i=0; i < nr_digis; i++){
fprintf(fp,"D,%s,%lu,",dtab[i].call,dtab[i].t_packets);
fprintf(fp,"%lu\n",dtab[i].t_bytes);
}
printf("\n Writing %d circuit records...",nr_circuits);
for(i=0; i < nr_circuits; i++){
fprintf(fp,"C,%s,%s,%d,",ctab[i].to,ctab[i].from,ctab[i].digis);
fprintf(fp,"%d,",ctab[i].pid);
fprintf(fp,"%lu,%lu,",ctab[i].u_dpackets,ctab[i].nd_dpackets);
fprintf(fp,"%lu,%lu,",ctab[i].t_dpackets,ctab[i].nd_packets);
fprintf(fp,"%lu,%lu,",ctab[i].t_packets,ctab[i].u_dbytes);
fprintf(fp,"%lu,",ctab[i].nd_dbytes);
fprintf(fp,"%lu,%lu,",ctab[i].t_dbytes,ctab[i].nd_bytes);
fprintf(fp,"%lu,",ctab[i].t_bytes);
fprintf(fp,"%lu,",ctab[i].c_time);
fprintf(fp,"%lu,%lu,%lu,",ctab[i].sabm,ctab[i].ua,ctab[i].disc);
fprintf(fp,"%lu,%lu,%lu,",ctab[i].dm,ctab[i].rej,ctab[i].rr);
fprintf(fp,"%lu,%lu,",ctab[i].rnr,ctab[i].i);
fprintf(fp,"%lu,%lu,",ctab[i].ui,ctab[i].frmr);
fprintf(fp,"%lu,%lu,%lu,",ctab[i].poll,ctab[i].final,ctab[i].l32);
fprintf(fp,"%lu,%lu,%lu,",ctab[i].l64,ctab[i].l128,ctab[i].l256);
fprintf(fp,"%lu\n",ctab[i].g256);
}
printf("\n Closing LOG file...}");
if(fclose(fp))
err_exit("Closing LOG file.");
printf("\n");
init_freq();
time(&start_time);
write_time = start_time + DUMP_INTERVAL;
}
/*
Build an ASCII callsign from left shifted AX.25 format
callsign.
*/
bcall(from,to)
unsigned char *from;
unsigned char *to;
{
int i;
unsigned char c,*tmp;
tmp = to;
for(i=0; i < 6; i++){
c = *from++ >> 1;
if(c != ' ')
*to++ = c;
}
if(tmp == to){
sprintf(to,"BLANK");
}
else{
c = (*from >>1) & 0xf;
if(c)
sprintf(to,"-%d",c);
else
*to = 0;
}
}
/*
Clear the frequency wide statistical counters.
*/
init_freq()
{
freq.t_packets =
freq.t_bytes =
freq.u_packets =
freq.u_bytes =
freq.l32 =
freq.l64 =
freq.l128 =
freq.l256 =
freq.g256 = 0l;
nr_circuits =
nr_digis = 0;
}
/*
Gather statistics on Digipeater activity
*/
do_digi(dptr)
unsigned char *dptr;
{
int i;
unsigned char digi_call[10];
bcall(dptr,digi_call);
/* lookup digipeater callsign in digipeater table */
for(i=0; i < nr_digis; i++){
if(!strcmp(dtab[i].call,digi_call)){
dtab[i].t_packets++;
dtab[i].t_bytes += frame_size;
return;
}
}
/* check for table overflow */
if(i == MAX_DIGIS){
printf("\007Error: The digipeater table is full!\n");
return;
}
/* initialize new digipeater table entry */
nr_digis++;
strcpy(dtab[i].call,digi_call);
dtab[i].t_packets = 1l;
dtab[i].t_bytes = frame_size;
}
/*
Print fatal error message, shutdown background interrupt
processes and exit.
*/
err_exit(string)
char *string;
{
printf("\007Error: %s\n",string);
if(!using_combios)
serldone();
tick_stop();
exit();
}
/*
Process keystrokes entered by user
*/
do_kbhit()
{
unsigned char kbdata;
kbdata = getch();
if(kbdata == 0){
kbdata = getch();
if (kbdata == 45/*X*/) {
/* ALT-X - exit */
if(ints_active)
serldone();
tick_stop();
dump_data();
exit();
}
else if (kbdata == 46/*C*/) {
cprintf("cmd:");
parse(0,NULL);
}
}
}
/*
Print Call in AX.25 left shifted format. Add an
'*' after call if it's an digipeater and the has been
digipeated bit is set and the next digipeater's bit is
not set.
*/
pcall(string,flag)
unsigned char *string;
int flag; /* set if call is a digipeater call */
{
int i;
char c;
/* print the callsign */
for(i = 0; i< 6; i++){
c=*string++ >> 1;
if(c != ' ')
putchar(c);
}
/* display SSID if there is one */
c=(*string >> 1) & 0xf;
if(c)
printf("-%d",c);
/* display the has been digipeated bit if appropriate */
if (flag) {
if(*string & 0x80 && (*string & 1 || !(string[7] & 0x80)))
putchar('*');
}
}
/*
Process the digipeaters heard bit map, set the global retry flag
if the frame has been heard from this hop before.
*/
do_bitmap(bit_map)
unsigned int *bit_map;
{
if(*bit_map & digi_bit){
/* this digi was heard before, this must be a retry */
*bit_map = digi_bit; /* clear other bits */
dnum = cnum; /* increment nd counters */
retry = TRUE;
}
else if(*bit_map){
/* some other digi was heard, this must be another */
/* digipeater hop, don't do nd counters */
*bit_map |= digi_bit; /* set our bit */
dnum = nr_circuits; /* don't do nd counters, point */
/* dnum somewhere harmless */
retry = FALSE;
}
else{
/* no one was heard from before, this must be */
/* the first time this packet was heard */
*bit_map |= digi_bit; /* set our bit */
dnum = cnum; /* increment nd counters */
retry = FALSE;
}
}